﻿//Created by Action Script Viewer - http://www.buraks.com/asv
package Engine.Classes {
    import Engine.Interfaces.*;
    import flash.display.*;
    import flash.geom.*;
    import Engine.Helpers.*;
    import Engine.*;

	/**
	 *	地图物品的基类， 对比PositionedObject多了depthIndex, outer等渲染相关的熟悉，还实现了地图的不少相关操作
	 */
    public class WorldObject extends PositionedObject implements IEngineObject, IRenderObject {

        private static var scratchv3:Vector3 = new Vector3();

        protected var m_typeName:String;
        protected var m_outer:World;
        protected var m_direction:int;
        protected var m_depthIndex:int = 0;
        protected var m_collisionFlags:int = 32;
        protected var m_parent:WorldObject = null;
        protected var m_children:Array;
        private var m_lastUpdateTime:Number = 0;
        public var renderBufferDirty:Boolean = true;
        private var m_shard:int = 0;
        private var rendering:Boolean = false;
        protected var m_animationBucket:int;

        public function WorldObject(){
            this.m_children = new Array();
            super();
        }
        public function get children():Array{
            return ([]);
        }
        public function getTypeName():String{
            return (this.m_typeName);
        }
        public function getReferencedAssets():Array{
            return ([]);
        }
        override public function getSaveObject():Object{
            var _local1:Object = super.getSaveObject();
            _local1.direction = this.m_direction;
            return (_local1);
        }
        override public function loadObject(_arg1:Object):void{
            super.loadObject(_arg1);
            this.m_direction = _arg1.direction;
        }
        public function cleanUp():void{
            this.m_outer = null;
            this.m_parent = null;
            this.m_children = [];
        }
        final public function update():void{
            var _local2:Number;
            if (this.m_outer){
				
				// 这套逻辑实现了每个物品每秒只会被update一次 
                _local2 = this.m_outer.getShardDelta(this.m_shard);
                if (_local2 >= 0){
                    onUpdate(_local2);
                };
            };
            var _local1:int;
            while (_local1 < this.m_children.length) {
                this.m_children[_local1].update();
                _local1++;
            };
        }
        public function render(_arg1:RenderContext):void{
        }
        protected function setObjectsDirty():void{
            if (this.m_outer){
                this.m_outer.setObjectsDirty();
            };
        }
        override public function markForDeletion(_arg1:Boolean):void{
            super.markForDeletion(_arg1);
            if (_arg1){
                this.m_outer.addToDeletionList(this);
            } else {
                this.m_outer.removeFromDeletionList(this);
            };
        }
        public function incrementTransactionsForChildren():void{
            var _local1:int;
            while (_local1 < this.m_children.length) {
                this.m_children[_local1].incrementTransactions();
                _local1++;
            };
        }
        public function decrementTransactionsForChildren():void{
            var _local1:int;
            while (_local1 < this.m_children.length) {
                this.m_children[_local1].decrementTransactions();
                _local1++;
            };
        }
        public function isIntersecting(_arg1:WorldObject):Boolean{
            var _local2:Vector3 = this.getDepthPositionNoClone();
            var _local3:Vector3 = this.getDepthSize();
            var _local4:Vector3 = _arg1.getDepthPositionNoClone();
            var _local5:Vector3 = _arg1.getDepthSize();
            var _local6:Vector3 = _local2.add(_local3);
            var _local7:Vector3 = _local4.add(_local5);
            var _local8:Boolean;
            if ((((((((((((_local6.x < _local4.x)) || ((_local2.x > _local7.x)))) || ((_local6.y < _local4.y)))) || ((_local2.y > _local7.y)))) || ((_local6.z < _local4.z)))) || ((_local2.z > _local7.z)))){
                _local8 = false;
            } else {
                if ((((((((((((_local3.x == 0)) && ((_local5.x > 0)))) && ((((_local4.x >= _local2.x)) || ((_local7.x <= _local2.x)))))) || ((((((_local3.y == 0)) && ((_local5.y > 0)))) && ((((_local4.y >= _local2.y)) || ((_local7.y <= _local2.y)))))))) || ((((((_local5.x == 0)) && ((_local3.x > 0)))) && ((((_local2.x >= _local4.x)) || ((_local6.x <= _local4.x)))))))) || ((((((_local5.y == 0)) && ((_local3.y > 0)))) && ((((_local2.y >= _local4.y)) || ((_local6.y <= _local4.y)))))))){
                    _local8 = false;
                } else {
                    _local8 = true;
                };
            };
            return (_local8);
        }
        override public function setPosition(_arg1:Number, _arg2:Number, _arg3:Number=0):void{
            var _local4:Vector3;
            var _local5:int;
            var _local6:WorldObject;
            if (((((!((m_position.x == _arg1))) || (!((m_position.y == _arg2))))) || (!((m_position.z == _arg3))))){
                _local4 = new Vector3((_arg1 - m_position.x), (_arg2 - m_position.y), (_arg3 - m_position.z));
                m_position = new Vector3(_arg1, _arg2, _arg3);
                if (this.m_outer != null){
                    m_screenPosition = IsoMath.tilePosToPixelPos(m_position.x, m_position.y, m_position.z, true);
                };
                m_transformDirty = true;
                _local5 = 0;
                while (_local5 < this.m_children.length) {
                    _local6 = (this.m_children[_local5] as WorldObject);
                    _local6.translate(_local4);
                    _local5++;
                };
            };
        }
        public function setDirection(_arg1:int):void{
            this.m_direction = _arg1;
        }
        public function setCollisionFlags(_arg1:uint):void{
            this.m_collisionFlags = _arg1;
        }
        public function getCollisionFlags(_arg1:int, _arg2:int):int{
            return (this.m_collisionFlags);
        }
        public function checkInternalCollision(_arg1:int, _arg2:int, _arg3:int):Boolean{
            return (CollisionMap.compareCollisionFlags(this.getCollisionFlags(_arg1, _arg2), _arg3));
        }
        public function setOuter(_arg1:World):void{
            this.m_outer = _arg1;
            if (_arg1 != null){
                this.m_shard = this.m_outer.getRandomShard();	// 从外层随机获取的一个Shard
            };
        }
        public function getOuter():PositionedObjectContainer{
            return (this.m_outer);
        }
        public function getDirection():int{
            return (this.m_direction);
        }
        public function getDepthSize():Vector3{
            return (m_size.clone());
        }
        public function getDepthPriority():Number{
            return (0);
        }
        public function getDepthPosition():Vector3{
            return (m_position.clone());
        }
        public function getDepthPositionNoClone():Vector3{
            return (m_position);
        }
        public function isCollidable():Boolean{
            return (!((this.m_collisionFlags == 0)));
        }
        protected function getLayerName():String{
            return (null);
        }
		
        public function attach():void{
            GlobalEngine.assert(!((this.m_outer == null)), "Outer for WorldObject is null!");
            if (m_attachPosition == null){
                this.calculateDepthIndex();
                this.m_outer.insertObjectIntoDepthArray(this, this.getLayerName());
                this.setObjectsDirty();
                this.m_outer.insertObjectIntoCollisionMap(this);
                this.m_animationBucket = this.m_outer.insertItemIntoAnimationBucket(this);
                updateDisplayObjectTransform();
                this.updateCulling();
                m_attachPosition = m_position.clone();
                m_attachSize = m_size.clone();
                m_transformDirty = false;
            };
        }
        public function detach():void{
            if (((!((m_attachPosition == null))) && (!((this.m_outer == null))))){
                this.m_outer.removeObjectFromCollisionMap(this);
                this.m_outer.removeObjectFromDepthArray(this);
                this.m_outer.removeItemFromAnimationBucket(this, this.m_animationBucket);
                m_attachPosition = null;
                m_attachSize = null;
                m_displayObjectDirty = true;
                this.setObjectsDirty();
            };
        }
        public function detatch():void{
            this.detach();
        }
		
        public function conditionallyRedraw(_arg1:Boolean=false):void{
            if (((((!((this.m_outer == null))) && ((this.m_outer.isRedrawLocked() == false)))) && (((m_displayObjectDirty) || (_arg1))))){
                if (this.rendering){
                    return;
                };
                this.rendering = true;
                drawDisplayObject();
                this.rendering = false;
                this.updateCulling();
                this.toggleAnimation();
                m_displayObjectDirty = false;
            };
        }
        public function conditionallyReattach(_arg1:Boolean=false):void{
            var _local3:WorldObject;
            if (isAttached() == false){
                this.attach();
            } else {
                if (((((((_arg1) || (m_transformDirty))) || (m_displayObjectDirty))) || ((m_attachPosition == null)))){
                    this.m_outer.removeObjectFromCollisionMap(this);
                    this.setObjectsDirty();
                    if (m_displayObjectDirty){
                        drawDisplayObject();
                    } else {
                        updateDisplayObjectTransform();
                    };
                    this.calculateDepthIndex();
                    this.m_outer.updateObjectInDepthArray(this);
                    this.m_outer.insertObjectIntoCollisionMap(this);
                    this.updateCulling();
                    m_attachPosition = m_position.clone();
                    m_attachSize = m_size.clone();
                    m_transformDirty = false;
                };
            };
            var _local2:int;
            while (_local2 < this.m_children.length) {
                _local3 = (this.m_children[_local2] as WorldObject);
                _local3.conditionallyReattach();
                _local2++;
            };
        }
        override public function updateCulling():void{
            var _local2:PositionedObject;
            super.updateCulling();
            var _local1:int;
            while (_local1 < this.m_children.length) {
                _local2 = (this.m_children[_local1] as PositionedObject);
                if (_local2 != null){
                    _local2.updateCulling();
                };
                _local1++;
            };
        }
        public function getBoundingBoxSprite(_arg1:Sprite=null):DisplayObject{
            if (_arg1 == null){
                _arg1 = new Sprite();
            };
            var _local2:Point = IsoMath.tilePosToPixelPos(m_position.x, m_position.y, m_position.z);
            var _local3:Point = IsoMath.tilePosToPixelPos((m_position.x + m_size.x), m_position.y, m_position.z);
            var _local4:Point = IsoMath.tilePosToPixelPos(m_position.x, (m_position.y + m_size.y), m_position.z);
            var _local5:Point = IsoMath.tilePosToPixelPos((m_position.x + m_size.x), (m_position.y + m_size.y), m_position.z);
            _arg1.graphics.lineStyle(3, 0xFF6600);
            _arg1.graphics.moveTo(_local2.x, _local2.y);
            _arg1.graphics.lineTo(_local2.x, (_local2.y - m_size.z));
            _arg1.graphics.lineTo(_local4.x, (_local4.y - m_size.z));
            _arg1.graphics.lineTo(_local4.x, _local4.y);
            _arg1.graphics.lineTo(_local2.x, _local2.y);
            return (_arg1);
        }
		
		/**
		 *	
		 */
        public function getFurthestTilePosition():Vector3{
            var _local1:Vector3 = this.getDepthPositionNoClone();
            var _local2:Vector3 = this.getDepthSize();
            var _local3:World = World.getInstance();
            var _local4:Vector3 = scratchv3;
            scratchv3.x = (scratchv3.y = (scratchv3.z = 0));
            switch (_local3.getRotation()){
                case Constants.ROTATION_0:
                    _local4.x = _local2.x;
                    _local4.y = _local2.y;
                    break;
                case Constants.ROTATION_90:
                    _local4.y = _local2.y;
                    break;
                case Constants.ROTATION_180:
                    break;
                case Constants.ROTATION_270:
                    _local4.x = _local2.x;
                    break;
            };
            return (_local1.add(_local4));
        }
		/**
		 *  depthIndex的计算规则是：（物品Tile的中心点的x和y坐标之和）*1000+物品Tile的中心点的x.
		 *  depthIndex主要用于物品的摆放层次
		 * 
		 */
        protected function calculateDepthIndex():void{
            var _local1:Vector3 = this.getNearestTilePosition();
            var _local2:Vector3 = this.getFurthestTilePosition();
            var _local3:Number = ((_local1.x + _local2.x) / 2);
            this.m_depthIndex = (((_local3 + ((_local1.y + _local2.y) / 2)) * 1000) + _local3);
        }
        public function get depthIndex():Number{
            return (this.m_depthIndex);
        }
		/**
		 * 取当前对象的Tile最近的一个点 
		 */
        public function getNearestTilePosition():Vector3{
            return (this.getOriginPoint(this.m_outer.getRotation()));
        }
        public function getOriginPoint(_arg1:int):Vector3{
            var _local2:Vector3 = this.getDepthPositionNoClone();
            var _local3:Vector3 = this.getDepthSize();
            var _local4:Vector3 = scratchv3;
            scratchv3.x = (scratchv3.y = (scratchv3.z = 0));
            switch (_arg1){
                case Constants.ROTATION_0:
                    break;
                case Constants.ROTATION_90:
                    _local4.x = Math.max(0, _local3.x);
                    break;
                case Constants.ROTATION_180:
                    _local4.x = Math.max(0, _local3.x);
                    _local4.y = Math.max(0, _local3.y);
                    break;
                case Constants.ROTATION_270:
                    _local4.y = Math.max(0, _local3.y);
                    break;
            };
            return (_local2.add(_local4));
        }
        public function compareDepth(_arg1:WorldObject):int{
            var _local5:Number;
            var _local6:Number;
            var _local2:int;
            if (_arg1.getParent() == this){
                return (1);
            };
            if (this.getParent() == _arg1){
                return (-1);
            };
            if (this.isIntersecting(_arg1)){
                _local5 = this.getDepthPriority();
                _local6 = _arg1.getDepthPriority();
                if (_local5 < _local6){
                    return (1);
                };
                if (_local5 > _local6){
                    return (-1);
                };
            };
            var _local3:Number = this.depthIndex;
            var _local4:Number = _arg1.depthIndex;
            if (_local3 < _local4){
                _local2 = -1;
            } else {
                if (_local4 < _local3){
                    _local2 = 1;
                } else {
                    _local2 = 0;
                };
            };
            return (_local2);
        }
        public function getChildren():Array{
            return (this.m_children.concat([]));
        }
        public function setParent(_arg1:WorldObject):void{
            if (this.m_parent != _arg1){
                if (this.m_parent != null){
                    this.m_parent.removeChild(this);
                };
                this.m_parent = _arg1;
                if (_arg1 != null){
                    _arg1.addChild(this);
                };
                m_transformDirty = true;
                this.onParentChanged();
            };
        }
        public function getParent():WorldObject{
            return (this.m_parent);
        }
        public function addChild(_arg1:WorldObject):void{
            if (this.m_children.indexOf(_arg1) == -1){
                this.m_children.push(_arg1);
                if (_arg1.getParent() != this){
                    _arg1.setParent(this);
                };
            };
        }
        public function removeChild(_arg1:WorldObject):void{
            var _local2:int = this.m_children.indexOf(_arg1);
            if (_local2 != -1){
                this.m_children.splice(_local2, 1);
                if (_arg1.getParent() == this){
                    _arg1.setParent(null);
                };
            };
        }
        public function removeAllChildren():void{
            var _local3:WorldObject;
            var _local1:Array = this.getChildren();
            var _local2:int;
            while (_local2 < _local1.length) {
                _local3 = (_local1[_local2] as WorldObject);
                _local3.setParent(null);
                _local2++;
            };
            this.m_children = [];
        }
        public function isChild(_arg1:WorldObject):Boolean{
            return (!((this.m_children.indexOf(_arg1) == -1)));
        }
        public function onParentChanged():void{
        }
        public function toggleAnimation():void{
        }
        public function centerOn():void{
            World.getInstance().centerOnObject(this);
        }
        public function cleanup():void{
        }

    }
}//package Engine.Classes 
